package com.wlx.gateway.handler;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.wlx.common.core.constant.Constants;
import com.wlx.common.core.utils.DateUtils;
import com.wlx.common.core.utils.ReUtil;
import com.wlx.common.core.utils.SmsCodeGenerator;
import com.wlx.common.core.utils.StringUtils;
import com.wlx.common.core.web.domain.AjaxResult;
import com.wlx.common.message.manager.SenderManagerService;
import com.wlx.common.redis.service.RedisService;
import com.wlx.gateway.config.properties.SenderProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * 邮箱/短信验证码获取
 *
 * @author wlx
 */
@Component
public class SendCodeHandler implements HandlerFunction<ServerResponse> {
    @Resource
    private SenderManagerService senderManagerService;

    @Resource
    private SenderProperties senderProperties;

    @Autowired
    private RedisService redisService;

    @SentinelResource(value = "/send", blockHandler = "sentinelGatewayExceptionHandler")
    @Override
    public Mono<ServerResponse> handle(ServerRequest serverRequest) {
        AjaxResult ajax = AjaxResult.success();
        try {
            Optional<String> typeOptional = serverRequest.queryParam("type");
            Optional<String> receiverOptional = serverRequest.queryParam("receiver");
            Optional<String> appIdOptional = serverRequest.queryParam("appId");
            String type = typeOptional.orElse(null);
            String receiver = receiverOptional.orElse(null);
            String appId = appIdOptional.orElse(null);

            if (StringUtils.isAnyBlank(appId, type, receiver)) {
                ajax = AjaxResult.error("应用ID/发送类型/接收者均不能为空");
            } else {
                //校验应用是否存在
                //@TODO 应用签名校验模式
                List<String> cacheList = redisService.getCacheList(Constants.APP_LIST_KEY);
                if (StringUtils.isNull(cacheList) || cacheList.size() == 0 || !cacheList.contains(appId)) {
                    ajax = AjaxResult.error("应用信息不存在");
                } else {
                    if (!ReUtil.isEmailNO(receiver) && !ReUtil.isMobileNO(receiver)) {
                        ajax = AjaxResult.error("请输入正确的手机号/邮箱");
                    } else {
                        String limitKey = Constants.RECEIVER_LIMIT_KEY + appId + ":" + receiver;
                        Integer dayLimit = redisService.getCacheObject(limitKey);
                        Integer limitDay = senderProperties.getLimitDay();
                        if (StringUtils.isNotNull(dayLimit) && StringUtils.isNotNull(limitDay) && dayLimit.intValue() >= limitDay.intValue()) {
                            ajax = AjaxResult.error("已超过当日发送限制，请联系系统管理员");
                        } else {
                            String randomCode = SmsCodeGenerator.randomCode();
                            String content = "您的验证码为：" + randomCode + "（2分钟内有效）";
                            boolean send = false;
                            if ("normal".equals(type)) {
                                ajax = AjaxResult.success("操作成功", "【蓝星云平台】" + content);
                                send = true;
                            } else {
                                String senderCode = senderProperties.getSenderCode();
                                send = senderManagerService.send(senderCode, receiver, content, null, type, senderProperties.getMaps());
                            }
                            if (!send) {
                                ajax = AjaxResult.error("发送失败");
                            } else {
                                if (redisService.hasKey(limitKey)) {
                                    redisService.increment(limitKey, 1L);
                                } else {
                                    Date curr = new Date();
                                    Date dateEndTime = DateUtils.getDateEndTime(curr);
                                    Long betweenMin = DateUtils.getBetweenMin(dateEndTime, curr);
                                    redisService.setCacheObject(limitKey, 1, betweenMin, TimeUnit.MINUTES);
                                }
                                String verifyKey = Constants.RECEIVER_CODE_KEY + appId + ":" + receiver;
                                redisService.setCacheObject(verifyKey, randomCode, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
                            }
                        }
                    }
                }
            }

        } catch (Exception e) {
            return Mono.error(e);
        }
        return ServerResponse.status(HttpStatus.OK).body(BodyInserters.fromValue(ajax));
    }

}